package com.puzzlebazar.client.main.control;

import java.util.HashMap;

import com.google.gwt.user.client.Window;
import com.puzzlebazar.client.main.control.EditPuzzleState.Type;
import com.puzzlebazar.client.main.view.MainView;
import com.puzzlebazar.client.puzzleinfo.PuzzleAndHistoryInfo;
import com.puzzlebazar.client.puzzleinfo.PuzzleInfo;
import com.puzzlebazar.client.services.PuzzleServiceAsync;
import com.puzzlebazar.client.services.ServiceFactory;
import com.puzzlebazar.client.user.UserModel;
import com.puzzlebazar.client.util.ConnectionLock;
import com.puzzlebazar.client.util.AsyncCallbackLock;

public class LoadPuzzleState extends MainState {

	public static final String STATE_TOKEN = "LoadPuzzle";
	private static final String KEY = "Key";
	private static final String TYPE = "Type";

	private final ConnectionLock connectionLock = new ConnectionLock( "Loading..." );
	
	private String key = null;
	private Type type = Type.PLAY_PUZZLE;

	public LoadPuzzleState( UserModel model, MainView view, MainController controller ) {
		super( model, view, controller );
		connectionLock.setGlobalLock( true );
	}

	@Override
	public String getStateToken() {
		return STATE_TOKEN;
	}

	/**
	 * Get the current parameters of the state provided the information
	 * 
	 * @param key Either a puzzle info key or a history info key
	 * @param type The edition/playing type for the puzzle
	 * @return The parameters of the state
	 */
	public static HashMap<String,String> getParams( String key, Type type) {
		final HashMap<String,String> params = new HashMap<String,String>();
		params.put( KEY, key );
		params.put( TYPE, type.toString() );
		return params;
	}

	@Override
	public HashMap<String,String> getParams() {
		return getParams( key, type );
	}

	/**
	 * Sets the parameters for the puzzle to load
	 * 
	 * @param key The key to the puzzle info or history info to load
	 * @param type The edition/playing type for the puzzle
	 */
	public void setParams( String key, Type type ) {
		this.key = key;
		this.type = type;
	}

	@Override
	public void setParams( HashMap<String,String> params ) throws Exception {
		try {
			setParams(
					params.get( KEY ),
					Type.valueOf( params.get( TYPE ) ) );
		}
		catch( Exception exception ) {
			setParams( null, Type.PLAY_PUZZLE );
			throw new Exception( "Invalid parameters" );
		}
	}
	
	@Override
	public void enter() {
		if( key == null ) {
			controller.backToPreviousState();
		}
			
		PuzzleServiceAsync puzzleService = ServiceFactory.getPuzzleService();
		
		switch( type ) {
		case CONTINUE_PUZZLE:
		case VIEW_SOLUTION:
			puzzleService.loadHistory( key, new LoadHistoryCallback(connectionLock) );
			break;
		case PLAY_PUZZLE:
		case EDIT_PUZZLE:
			puzzleService.loadPuzzle( key, new LoadPuzzleCallback(connectionLock) );
			break;
		case EDIT_TUTORIAL:
		case VIEW_TUTORIAL:
			puzzleService.loadTutorial( key, new LoadHistoryCallback(connectionLock) );
			break;
		}
	}

	@Override
	public void exit() {
		key = null;
	}



	private class LoadPuzzleCallback extends AsyncCallbackLock<PuzzleInfo> {

		public LoadPuzzleCallback(ConnectionLock lock) {
			super(lock);
		}

		@Override
		public void onFailure(Throwable caught) {
			super.onFailure( caught );
			failed();
		}

		@Override
		public void onSuccess(PuzzleInfo info) {
			super.onSuccess( info );
			if( info == null )
				failed();
			else
				controller.switchToEditLoadedPuzzle( info, null, type );
		}

		private void failed() {
			Window.alert( "Load failed!" );
			controller.backToPreviousState();
		}
	}



	private class LoadHistoryCallback extends AsyncCallbackLock<PuzzleAndHistoryInfo> {

		public LoadHistoryCallback(ConnectionLock lock) {
			super(lock);
		}

		@Override
		public void onFailure(Throwable caught) {
			super.onFailure( caught );
			failed();
		}

		@Override
		public void onSuccess(PuzzleAndHistoryInfo info) {
			super.onSuccess( info );
			if( info == null )
				failed();
			else
				controller.switchToEditLoadedPuzzle( info.getPuzzleInfo(), info.getHistoryInfo(), type );
		}

		private void failed() {
			Window.alert( "Load failed!" );
			controller.backToPreviousState();
		}
	}

	@Override
	public void release() {
		super.release();
	}	
	
}
